<?php

require_once '../DAO/Conexao.php';

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/**
 * Description of Model
 *
 * @author david
 */
class Model {

    public $p = null;
    private $values = [];
    private $table_name = null;
    private $object = null;
    private $conditions = [];
    private $sql = null;
    private $action = null;
    private $attr = null;
    private $entity = null;
    private $qtde_column = null;
    private $inner = null;

    public function Model() {
        $this->p = Conexao::Intancia()->Db();
    }

    public function persistir($class, $object) {
        $attrObject = $this->attributsEntity($object);

        // salva a action para usar no addConditionsAndValues
        $this->action = $object->action;

        $class = ucwords($class);
        $this->entity = new $class;
        $attrEntity = $this->attributsEntity($this->entity);

        if ($attrEntity != $attrObject) {
            return "erro";
        }

        $this->object = $object;
        $this->attr = $attrObject;
        $this->table_name = strtolower($class);

        $this->addConditionsAndValues($class, $object);

        $this->qtde_column = count($this->values);

        switch ($this->object->action) {
            case "list":
                $result = $this->execList();
                break;

            case "new":
                $result = $this->execNew();
                break;

            case "update":
                $result = $this->execUpdate();
                break;

            case "delete":
                $result = $this->execDelete();
                break;

            default :
                $result = "erro";
                break;
        }

        return $result;
    }

    public function execList() {
        $this->sql = "SELECT ";
        $this->addAtributosSelect($this->table_name, $this->values);

        $this->sql .= " FROM " . strtolower($this->table_name);

        $i = 0;

        // adiciona os inner join
        if (isset($this->inner)) {
            $this->sql .= $this->inner;
        }

        // adiciona as condições de WHERE no SQL
        if (!empty($this->conditions)) {
            $this->sql .= " WHERE ";
            foreach ($this->conditions as $key => $condition) {
                if ($i > 0) {
                    $this->sql .= " AND ";
                }
                $this->sql .= $key . " = ?";
                $i++;
            }
        }

        return $result = $this->execSQL();
    }

    public function execNew() {
        $this->sql = "INSERT INTO ";
        $this->sql .= $this->table_name . " (";

        $i = 1;

        $values = "";
        foreach ($this->values as $column) {
            $column = strtolower($column);
            $explode = explode(".", $column);

            if (!($explode[0] == $this->table_name && $explode[1] == "codigo")) {
                if ($explode[0] == $this->table_name) {
                    $this->sql .= $explode[1];
                } else {
                    $this->sql .= $explode[0];
                }

                $values .= "?";

                if ($i != $this->qtde_column) {
                    $this->sql .=", ";
                    $values .=", ";
                }
            }
            $i++;
        }

        $this->sql .= ") VALUES (" . $values . ");";

        return $result = $this->execSQL();
    }

    public function execUpdate() {
        $this->sql = "UPDATE ";
        $this->sql .= $this->table_name . " SET ";

        $i = 1;

        foreach ($this->values as $column) {
            $explode = explode(".", $column);

            if (!(strtolower($explode[0]) == $this->table_name && $explode[1] == "codigo")) {

                $auxEntity = strtolower($explode[0]);

                if ($auxEntity != $this->table_name) {
                    $this->sql .= $auxEntity . " = ?";
                } else {
                    $this->sql .= $explode[1] . " = ?";
                }

                if ($i != $this->qtde_column) {
                    $this->sql .=", ";
                }
            }
            $i++;
        }
        $this->sql .= " WHERE codigo = ?";

        unset($this->conditions["$this->table_name.codigo"]);

        $this->conditions["$this->table_name.codigo"] = $this->object->codigo;
        return $result = $this->execSQL();
    }

    public function execDelete() {
        $this->sql = "DELETE FROM ";
        $this->sql .= $this->table_name;

        $this->sql .= " WHERE codigo = ?";
        return $result = $this->execSQL();
    }

    public function execSQL() {
        $stmt = $this->p->prepare($this->sql);

        $index = 1;

        foreach ($this->conditions as $key => $condition) {

            // verifica se não é uma entidade e adiociona o valor no bind do SQL
            $stmt->bindValue($index, $condition, PDO::PARAM_STR);
            $index++;
        }
        
        $res = $stmt->execute();
        if ($res != 1) {
            $result = "erro";
        } else {
            if ($this->object->action == "list") {
                $result = $this->interator($stmt);
            } else {
                $result = $res;
            }
        }
        return $result;
    }

    public function interator($stmt) {
        //$class = ucfirst($this->table_name);
        $result = [];
        while ($linha = $stmt->fetch()) {
            //$entity = new $class;
            $cloneObject = clone $this->object;
            $objectLine = $this->setObject($cloneObject, $this->table_name, $linha);

            $result[] = $objectLine;
        }

        return $result;
    }

    // public function setObject($values, $entity, $linha) {
    public function setObject($object, $entity, $linha2) {
        $attrs = $this->attributsEntity($object);
        foreach ($attrs as $key => $attr) {
            if ($this->existEntity($key) && $object->$key != null) {
                $object->$key = $this->setObject($object->$key, $key, $linha2);
            } else if ($object->$key != null || $key == "codigo") {
                $column = strtolower("$entity.$key");
                $object->$key = $linha2[$column];
            }
        }

        return $object;
    }

    /**
     * Retorna todos os attributos da entidade
     * @param object $entity
     * @return type
     */
    public function attributsEntity($entity) {
        return get_class_vars(get_class($entity));
    }

    /**
     * Verifica se o dado é Entidade
     * @param object $entity
     * @return boolean
     */
    public function existEntity($entity) {
        $arquivoEntity = '../entity/' . ucfirst($entity) . ".php";
        if (file_exists($arquivoEntity)) {
            return true;
        } else {
            return false;
        }
    }

    public function addTablesInner($table, $inner) {
        $inner = strtolower($inner);
        $table = strtolower($table);
        $this->inner .= " INNER JOIN $inner ON $table.$inner = $inner.codigo";
    }

    public function addConditionsAndValues($class, $object) {
        $attrs = $this->attributsEntity($object);

        foreach ($attrs as $key => $attr) {
            if ($object->$key == "#" || ($key == "codigo" && $object->$key == null)) {
                $this->values[] = $class . "." . $key;
            } else if ($object->$key != null) {
                if ($this->existEntity($key)) {
                    $this->addTablesInner($class, $key);
                    $this->addConditionsAndValues($key, $object->$key);
                } else {
                    $this->values[] = $class . "." . $key;
                    if ($this->action == "list" || $this->action == "update") {
                        $this->conditions[strtolower("$class.$key")] = $object->$key;
                    } else {
                        $class = strtolower($class);
                        if ($class == $this->table_name) {
                            $this->conditions[strtolower("$key")] = $object->$key;
                        } else {
                            $this->conditions[strtolower("$class")] = $object->$key;
                        }
                    }
                }
            }
        }
    }

    public function addAtributosSelect() {
        foreach ($this->values as $key => $column) {
            $this->sql .= strtolower($column) . strtolower(" as '$column'");
            if ($key + 1 != count($this->values)) {
                $this->sql .= ", ";
            }
        }
    }

}